ROS2 Humble 跨设备 DDS 组播通信配置指南
适用场景:在 Windows 侧 WSL 的 RViz2 中实时显示远端 Jetson Xavier NX 上 ROS2 发布的话题(LiDAR 点云、TF、地图等)。
一、网络拓扑总览
本方案涉及多层嵌套环境,从外到内的完整链路如下:
┌─────────────────────────────────────────────────────────────────────────┐
│ Windows 11 主机 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ WSL2 - Ubuntu 22.04 │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ ROS2 Humble │ │ │
│ │ │ - RViz2(可视化) │ │ │
│ │ │ - ros2 topic list / echo(调试) │ │ │
│ │ │ 网卡: eth2 IP: 192.168.3.182 │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │
│ WiFi 局域网 │
│ 192.168.3.0/24 │
│ │ │
└──────────────────────────┼──────────────────────────────────────────────┘
│
┌──────────────────────────┼──────────────────────────────────────────────┐
│ Jetson Xavier NX(宿主机 Ubuntu 20.04) │
│ 网卡: wlan0 IP: 192.168.3.214 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Docker 容器(--network=host) │ │
│ │ Ubuntu 22.04 │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ ROS2 Humble │ │ │
│ │ │ - 各类节点(LiDAR驱动、导航、定位等) │ │ │
│ │ │ - 话题发布者 │ │ │
│ │ │ 共享宿主机网络栈(host 模式) │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘关键点说明:
- WSL2 的
eth2网卡已桥接到宿主机的物理 WiFi 网卡,与 Jetson 处于同一个192.168.3.0/24子网,可以互相ping通。 - Jetson 侧 Docker 使用
--network=host模式,容器直接共享宿主机的网络栈,无需额外端口映射。 - 两侧 ROS2 均使用默认的 FastDDS 中间件,通过 UDP 组播(Multicast) 进行节点自动发现。
二、DDS 组播发现原理(简述)
ROS2 默认使用 FastDDS 作为 DDS 中间件,节点发现依赖 RTPS 协议的组播机制:
- 每个 ROS2 节点启动时,会向组播地址
239.255.0.1的对应端口发送 Participant Discovery Protocol (PDP) 公告。 - 同一
ROS_DOMAIN_ID下的所有节点监听同一个端口,因此能互相发现。 - 发现端口的计算公式为:
discovery_port = 7400 + 250 × ROS_DOMAIN_ID例如 ROS_DOMAIN_ID=6 时,发现端口为 7400 + 250 × 6 = 8900。
组播能通,节点就能互相发现——不需要任何额外的 DDS XML 配置。
三、前置条件检查清单
在开始配置之前,逐项确认以下条件:
3.1 网络互通
# WSL 中 ping Jetson
ping 192.168.3.214
# Jetson 中 ping WSL
ping 192.168.3.182双向均应 0% packet loss。如果 ping 不通,请先解决基础网络问题(WiFi 连接、WSL 网络模式等)。
3.2 Docker 网络模式
在 Jetson 宿主机上确认容器使用 host 网络:
docker inspect <容器名> | grep NetworkMode输出应为:
"NetworkMode": "host",如果不是
host模式,容器内的组播包无法直接通过宿主机的 wlan0 发出,需要改用--network=host重新创建容器。
3.3 DDS 中间件
两侧均应使用默认的 FastDDS(不需要手动安装或切换):
echo $RMW_IMPLEMENTATION无输出或输出 rmw_fastrtps_cpp 均为正确状态。如果输出了其他值(如 rmw_cyclonedds_cpp),需要统一为同一种 DDS 实现。
四、配置步骤
4.1 统一 ROS_DOMAIN_ID
两侧必须使用完全相同的 ROS_DOMAIN_ID,否则节点发现会在不同的端口上进行,永远无法互通。
WSL 侧(~/.bashrc):
echo 'export ROS_DOMAIN_ID=6' >> ~/.bashrc
source ~/.bashrcJetson Docker 侧(容器内 ~/.bashrc):
echo 'export ROS_DOMAIN_ID=6' >> ~/.bashrc
source ~/.bashrc验证:
echo $ROS_DOMAIN_ID
# 两侧都应输出: 6注意:
ROS_DOMAIN_ID的值可以是 0~232 之间的任意整数,只要两边一致即可。如果你的局域网中有其他 ROS2 设备不想互相干扰,可以选一个独特的数字。
4.2 关闭 ROS_LOCALHOST_ONLY
这个环境变量如果被设为 1,DDS 将只在本机通信,彻底屏蔽跨设备发现。
两侧都执行:
echo 'export ROS_LOCALHOST_ONLY=0' >> ~/.bashrc
source ~/.bashrc验证:
echo $ROS_LOCALHOST_ONLY
# 应输出: 0(或为空,空等价于 0)4.3 放行 Windows 防火墙(关键步骤)
这是整个配置中最容易被忽略也最关键的一步。
WSL2 的入站网络流量需要经过 Windows 防火墙,而 Windows 防火墙默认会拦截入站的 UDP 组播包,导致 WSL 中的 ROS2 节点无法收到 Jetson 发出的 DDS 发现公告。
症状表现为:Jetson 侧的 ros2 topic list 能看到 WSL 的话题,但 WSL 侧看不到 Jetson 的话题(单向不通)。
在 Windows 上以管理员身份打开 PowerShell,执行以下命令:
# 放行 DDS 发现端口(DOMAIN_ID=6 对应 8900)
# 如果你使用其他 DOMAIN_ID,请按公式 7400+250*ID 计算端口
New-NetFirewallRule -DisplayName "ROS2 DDS Discovery Inbound" `
-Direction Inbound `
-Protocol UDP `
-LocalPort 7400-7500,8900-9000 `
-Action Allow
# 放行 DDS 数据传输(用户流量端口范围较大)
New-NetFirewallRule -DisplayName "ROS2 DDS UserTraffic Inbound" `
-Direction Inbound `
-Protocol UDP `
-LocalPort 7400-65535 `
-Action Allow如果你不想精细管理端口,也可以用更简单粗暴的方式——直接放行所有 WSL 入站流量:
powershellNew-NetFirewallRule -DisplayName "WSL Inbound Allow All" ` -Direction Inbound ` -Program "C:\Windows\System32\wsl.exe" ` -Action Allow
验证防火墙规则是否生效:
Get-NetFirewallRule -DisplayName "ROS2*" | Format-Table Name, DisplayName, Enabled, Action五、验证通信
5.1 组播包抓包验证
在 WSL 中使用 tcpdump 确认能收到 Jetson 发出的组播包:
# 安装 tcpdump(如果没有)
sudo apt install -y tcpdump
# 抓取 DDS 发现端口的 UDP 包(DOMAIN_ID=6 → 端口 8900)
sudo tcpdump -i eth2 udp port 8900 -nn同时在 Jetson Docker 中随便发布一个话题:
source /opt/ros/humble/setup.bash
ros2 topic pub /test_topic std_msgs/msg/String "data: 'hello from jetson'" --rate 1预期结果: tcpdump 中应同时出现来自 192.168.3.182(WSL)和 192.168.3.214(Jetson)的 UDP 包。如果只有 WSL 自己的包,说明防火墙仍在拦截,请回到第 4.3 步检查。
5.2 ROS2 话题验证
# WSL 中
source /opt/ros/humble/setup.bash
# 列出所有可见话题
ros2 topic list
# 应能看到 /test_topic
# 查看话题数据
ros2 topic echo /test_topic输出应为:
data: hello from jetson
---
data: hello from jetson
---5.3 启动 RViz2
source /opt/ros/humble/setup.bash
rviz2在 RViz2 中:
- 左下角点击 Add
- 选择 By topic 标签页
- 展开列表,即可看到 Jetson 发布的所有话题
- 选中需要的话题类型(如 LaserScan、PointCloud2、TF、Map 等)点击 OK 添加
六、常见问题排查
Q1:ros2 topic list 只显示 /parameter_events 和 /rosout
原因:DDS 节点发现失败。按以下顺序排查:
- 检查
ROS_DOMAIN_ID两侧是否一致 - 检查
ROS_LOCALHOST_ONLY是否为 0 - 用 tcpdump 抓包确认组播包是否到达
- 检查 Windows 防火墙是否已放行
Q2:能看到话题但 ros2 topic echo 没有数据
原因:DDS 发现成功但数据传输被拦截。数据走的是另一组 UDP 端口。确保防火墙放行了足够宽的端口范围(建议 7400-65535 全放行)。
Q3:RViz2 显示话题但画面不更新或严重延迟
可能原因:
- WiFi 带宽不够(特别是点云数据量很大时),可以在发布侧降低频率或降采样
- QoS 不匹配,尝试在 RViz2 的话题设置中将 Reliability 改为 Best Effort
Q4:Docker 容器重启后配置丢失
如果容器不是用 docker commit 保存的,~/.bashrc 中的环境变量会丢失。建议在 docker run 命令中直接传入:
docker run -it --network=host \
-e ROS_DOMAIN_ID=6 \
-e ROS_LOCALHOST_ONLY=0 \
<镜像名> /bin/bash或写入 Dockerfile:
ENV ROS_DOMAIN_ID=6
ENV ROS_LOCALHOST_ONLY=0Q5:如何确认 DDS 发现端口号
discovery_port = 7400 + 250 × ROS_DOMAIN_ID| ROS_DOMAIN_ID | 发现端口 |
|---|---|
| 0 | 7400 |
| 1 | 7650 |
| 6 | 8900 |
| 10 | 9900 |
七、环境变量速查
以下环境变量建议写入两侧的 ~/.bashrc,确保每次启动终端自动生效:
# ====== ROS2 DDS 跨设备通信配置 ======
export ROS_DOMAIN_ID=6
export ROS_LOCALHOST_ONLY=0
# 以下为可选,不设也行(默认即为 FastDDS)
# export RMW_IMPLEMENTATION=rmw_fastrtps_cpp最后更新:2026-06-01 | 适用于 ROS2 Humble + FastDDS 默认组播方案
